

<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
  <meta charset="utf-8">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="Description" content="scikit-learn: machine learning in Python">

  
  <title>8. Computing with scikit-learn &mdash; scikit-learn 0.22 documentation</title>
  
  <link rel="canonical" href="http://scikit-learn.org/stable/modules/computing.html" />

  
  <link rel="shortcut icon" href="../_static/favicon.ico"/>
  

  <link rel="stylesheet" href="../_static/css/vendor/bootstrap.min.css" type="text/css" />
  <link rel="stylesheet" href="../_static/gallery.css" type="text/css" />
  <link rel="stylesheet" href="../_static/css/theme.css" type="text/css" />
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script> 
</head>
<body>
<nav id="navbar" class="sk-docs-navbar navbar navbar-expand-md navbar-light bg-light py-0">
  <div class="container-fluid sk-docs-container px-0">
      <a class="navbar-brand py-0" href="../index.html">
        <img
          class="sk-brand-img"
          src="../_static/scikit-learn-logo-small.png"
          alt="logo"/>
      </a>
    <button
      id="sk-navbar-toggler"
      class="navbar-toggler"
      type="button"
      data-toggle="collapse"
      data-target="#navbarSupportedContent"
      aria-controls="navbarSupportedContent"
      aria-expanded="false"
      aria-label="Toggle navigation"
    >
      <span class="navbar-toggler-icon"></span>
    </button>

    <div class="sk-navbar-collapse collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav mr-auto">
        <li class="nav-item">
          <a class="sk-nav-link nav-link" href="../install.html">Install</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link" href="../user_guide.html">User Guide</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link" href="classes.html">API</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link" href="../auto_examples/index.html">Examples</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../getting_started.html">Getting Started</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../tutorial/index.html">Tutorial</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../glossary.html">Glossary</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../developers/index.html">Development</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../faq.html">FAQ</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../related_projects.html">Related packages</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../roadmap.html">Roadmap</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../about.html">About us</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="https://github.com/scikit-learn/scikit-learn">GitHub</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="https://scikit-learn.org/dev/versions.html">Other Versions</a>
        </li>
        <li class="nav-item dropdown nav-more-item-dropdown">
          <a class="sk-nav-link nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">More</a>
          <div class="dropdown-menu" aria-labelledby="navbarDropdown">
              <a class="sk-nav-dropdown-item dropdown-item" href="../getting_started.html">Getting Started</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../tutorial/index.html">Tutorial</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../glossary.html">Glossary</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../developers/index.html">Development</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../faq.html">FAQ</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../related_projects.html">Related packages</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../roadmap.html">Roadmap</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../about.html">About us</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="https://github.com/scikit-learn/scikit-learn">GitHub</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="https://scikit-learn.org/dev/versions.html">Other Versions</a>
          </div>
        </li>
      </ul>
      <div id="searchbox" role="search">
          <div class="searchformwrapper">
          <form class="search" action="../search.html" method="get">
            <input class="sk-search-text-input" type="text" name="q" aria-labelledby="searchlabel" />
            <input class="sk-search-text-btn" type="submit" value="Go" />
          </form>
          </div>
      </div>
    </div>
  </div>
</nav>
<div class="d-flex" id="sk-doc-wrapper">
    <input type="checkbox" name="sk-toggle-checkbox" id="sk-toggle-checkbox">
    <label id="sk-sidemenu-toggle" class="sk-btn-toggle-toc btn sk-btn-primary" for="sk-toggle-checkbox">Toggle Menu</label>
    <div id="sk-sidebar-wrapper" class="border-right">
      <div class="sk-sidebar-toc-wrapper">
        <div class="sk-sidebar-toc-logo">
          <a href="../index.html">
            <img
              class="sk-brand-img"
              src="../_static/scikit-learn-logo-small.png"
              alt="logo"/>
          </a>
        </div>
        <div class="btn-group w-100 mb-2" role="group" aria-label="rellinks">
            <a href="../datasets/index.html" role="button" class="btn sk-btn-rellink py-1" sk-rellink-tooltip="7. Dataset loading utilities">Prev</a><a href="../user_guide.html" role="button" class="btn sk-btn-rellink py-1" sk-rellink-tooltip="User Guide">Up</a>
            <a href="../glossary.html" role="button" class="btn sk-btn-rellink py-1" sk-rellink-tooltip="Glossary of Common Terms and API Elements">Next</a>
        </div>
        <div class="alert alert-danger p-1 mb-2" role="alert">
          <p class="text-center mb-0">
          <strong>scikit-learn 0.22</strong><br/>
          <a href="http://scikit-learn.org/dev/versions.html">Other versions</a>
          </p>
        </div>
        <div class="alert alert-warning p-1 mb-2" role="alert">
          <p class="text-center mb-0">
            Please <a class="font-weight-bold" href="../about.html#citing-scikit-learn"><string>cite us</string></a> if you use the software.
          </p>
        </div>
          <div class="sk-sidebar-toc">
            <ul>
<li><a class="reference internal" href="#">8. Computing with scikit-learn</a><ul>
<li><a class="reference internal" href="#strategies-to-scale-computationally-bigger-data">8.1. Strategies to scale computationally: bigger data</a><ul>
<li><a class="reference internal" href="#scaling-with-instances-using-out-of-core-learning">8.1.1. Scaling with instances using out-of-core learning</a><ul>
<li><a class="reference internal" href="#streaming-instances">8.1.1.1. Streaming instances</a></li>
<li><a class="reference internal" href="#extracting-features">8.1.1.2. Extracting features</a></li>
<li><a class="reference internal" href="#incremental-learning">8.1.1.3. Incremental learning</a></li>
<li><a class="reference internal" href="#examples">8.1.1.4. Examples</a></li>
<li><a class="reference internal" href="#notes">8.1.1.5. Notes</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#computational-performance">8.2. Computational Performance</a><ul>
<li><a class="reference internal" href="#prediction-latency">8.2.1. Prediction Latency</a><ul>
<li><a class="reference internal" href="#bulk-versus-atomic-mode">8.2.1.1. Bulk versus Atomic mode</a></li>
<li><a class="reference internal" href="#configuring-scikit-learn-for-reduced-validation-overhead">8.2.1.2. Configuring Scikit-learn for reduced validation overhead</a></li>
<li><a class="reference internal" href="#influence-of-the-number-of-features">8.2.1.3. Influence of the Number of Features</a></li>
<li><a class="reference internal" href="#influence-of-the-input-data-representation">8.2.1.4. Influence of the Input Data Representation</a></li>
<li><a class="reference internal" href="#influence-of-the-model-complexity">8.2.1.5. Influence of the Model Complexity</a></li>
<li><a class="reference internal" href="#feature-extraction-latency">8.2.1.6. Feature Extraction Latency</a></li>
</ul>
</li>
<li><a class="reference internal" href="#prediction-throughput">8.2.2. Prediction Throughput</a></li>
<li><a class="reference internal" href="#tips-and-tricks">8.2.3. Tips and Tricks</a><ul>
<li><a class="reference internal" href="#linear-algebra-libraries">8.2.3.1. Linear algebra libraries</a></li>
<li><a class="reference internal" href="#limiting-working-memory">8.2.3.2. Limiting Working Memory</a></li>
<li><a class="reference internal" href="#model-compression">8.2.3.3. Model Compression</a></li>
<li><a class="reference internal" href="#model-reshaping">8.2.3.4. Model Reshaping</a></li>
<li><a class="reference internal" href="#links">8.2.3.5. Links</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#parallelism-resource-management-and-configuration">8.3. Parallelism, resource management, and configuration</a><ul>
<li><a class="reference internal" href="#parallelism">8.3.1. Parallelism</a><ul>
<li><a class="reference internal" href="#joblib-based-parallelism">8.3.1.1. Joblib-based parallelism</a></li>
<li><a class="reference internal" href="#openmp-based-parallelism">8.3.1.2. OpenMP-based parallelism</a></li>
<li><a class="reference internal" href="#parallel-numpy-routines-from-numerical-libraries">8.3.1.3. Parallel Numpy routines from numerical libraries</a></li>
<li><a class="reference internal" href="#oversubscription-spawning-too-many-threads">8.3.1.4. Oversubscription: spawning too many threads</a></li>
</ul>
</li>
<li><a class="reference internal" href="#configuration-switches">8.3.2. Configuration switches</a><ul>
<li><a class="reference internal" href="#python-runtime">8.3.2.1. Python runtime</a></li>
<li><a class="reference internal" href="#environment-variables">8.3.2.2. Environment variables</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>

          </div>
      </div>
    </div>
    <div id="sk-page-content-wrapper">
      <div class="sk-page-content container-fluid body px-md-3" role="main">
        
  <div class="section" id="computing-with-scikit-learn">
<h1>8. Computing with scikit-learn<a class="headerlink" href="#computing-with-scikit-learn" title="Permalink to this headline">¶</a></h1>
<div class="section" id="strategies-to-scale-computationally-bigger-data">
<span id="scaling-strategies"></span><h2>8.1. Strategies to scale computationally: bigger data<a class="headerlink" href="#strategies-to-scale-computationally-bigger-data" title="Permalink to this headline">¶</a></h2>
<p>For some applications the amount of examples, features (or both) and/or the
speed at which they need to be processed are challenging for traditional
approaches. In these cases scikit-learn has a number of options you can
consider to make your system scale.</p>
<div class="section" id="scaling-with-instances-using-out-of-core-learning">
<h3>8.1.1. Scaling with instances using out-of-core learning<a class="headerlink" href="#scaling-with-instances-using-out-of-core-learning" title="Permalink to this headline">¶</a></h3>
<p>Out-of-core (or “external memory”) learning is a technique used to learn from
data that cannot fit in a computer’s main memory (RAM).</p>
<p>Here is a sketch of a system designed to achieve this goal:</p>
<blockquote>
<div><ol class="arabic simple">
<li><p>a way to stream instances</p></li>
<li><p>a way to extract features from instances</p></li>
<li><p>an incremental algorithm</p></li>
</ol>
</div></blockquote>
<div class="section" id="streaming-instances">
<h4>8.1.1.1. Streaming instances<a class="headerlink" href="#streaming-instances" title="Permalink to this headline">¶</a></h4>
<p>Basically, 1. may be a reader that yields instances from files on a
hard drive, a database, from a network stream etc. However,
details on how to achieve this are beyond the scope of this documentation.</p>
</div>
<div class="section" id="extracting-features">
<h4>8.1.1.2. Extracting features<a class="headerlink" href="#extracting-features" title="Permalink to this headline">¶</a></h4>
<p>2. could be any relevant way to extract features among the
different <a class="reference internal" href="feature_extraction.html#feature-extraction"><span class="std std-ref">feature extraction</span></a> methods supported by
scikit-learn. However, when working with data that needs vectorization and
where the set of features or values is not known in advance one should take
explicit care. A good example is text classification where unknown terms are
likely to be found during training. It is possible to use a stateful
vectorizer if making multiple passes over the data is reasonable from an
application point of view. Otherwise, one can turn up the difficulty by using
a stateless feature extractor. Currently the preferred way to do this is to
use the so-called <a class="reference internal" href="feature_extraction.html#feature-hashing"><span class="std std-ref">hashing trick</span></a> as implemented by
<a class="reference internal" href="generated/sklearn.feature_extraction.FeatureHasher.html#sklearn.feature_extraction.FeatureHasher" title="sklearn.feature_extraction.FeatureHasher"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.feature_extraction.FeatureHasher</span></code></a> for datasets with categorical
variables represented as list of Python dicts or
<a class="reference internal" href="generated/sklearn.feature_extraction.text.HashingVectorizer.html#sklearn.feature_extraction.text.HashingVectorizer" title="sklearn.feature_extraction.text.HashingVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.feature_extraction.text.HashingVectorizer</span></code></a> for text documents.</p>
</div>
<div class="section" id="incremental-learning">
<h4>8.1.1.3. Incremental learning<a class="headerlink" href="#incremental-learning" title="Permalink to this headline">¶</a></h4>
<p>Finally, for 3. we have a number of options inside scikit-learn. Although not
all algorithms can learn incrementally (i.e. without seeing all the instances
at once), all estimators implementing the <code class="docutils literal notranslate"><span class="pre">partial_fit</span></code> API are candidates.
Actually, the ability to learn incrementally from a mini-batch of instances
(sometimes called “online learning”) is key to out-of-core learning as it
guarantees that at any given time there will be only a small amount of
instances in the main memory. Choosing a good size for the mini-batch that
balances relevancy and memory footprint could involve some tuning <a class="footnote-reference brackets" href="#id2" id="id1">1</a>.</p>
<p>Here is a list of incremental estimators for different tasks:</p>
<blockquote>
<div><ul class="simple">
<li><dl class="simple">
<dt>Classification</dt><dd><ul>
<li><p><a class="reference internal" href="generated/sklearn.naive_bayes.MultinomialNB.html#sklearn.naive_bayes.MultinomialNB" title="sklearn.naive_bayes.MultinomialNB"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.naive_bayes.MultinomialNB</span></code></a></p></li>
<li><p><a class="reference internal" href="generated/sklearn.naive_bayes.BernoulliNB.html#sklearn.naive_bayes.BernoulliNB" title="sklearn.naive_bayes.BernoulliNB"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.naive_bayes.BernoulliNB</span></code></a></p></li>
<li><p><a class="reference internal" href="generated/sklearn.linear_model.Perceptron.html#sklearn.linear_model.Perceptron" title="sklearn.linear_model.Perceptron"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.linear_model.Perceptron</span></code></a></p></li>
<li><p><a class="reference internal" href="generated/sklearn.linear_model.SGDClassifier.html#sklearn.linear_model.SGDClassifier" title="sklearn.linear_model.SGDClassifier"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.linear_model.SGDClassifier</span></code></a></p></li>
<li><p><a class="reference internal" href="generated/sklearn.linear_model.PassiveAggressiveClassifier.html#sklearn.linear_model.PassiveAggressiveClassifier" title="sklearn.linear_model.PassiveAggressiveClassifier"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.linear_model.PassiveAggressiveClassifier</span></code></a></p></li>
<li><p><a class="reference internal" href="generated/sklearn.neural_network.MLPClassifier.html#sklearn.neural_network.MLPClassifier" title="sklearn.neural_network.MLPClassifier"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.neural_network.MLPClassifier</span></code></a></p></li>
</ul>
</dd>
</dl>
</li>
<li><dl class="simple">
<dt>Regression</dt><dd><ul>
<li><p><a class="reference internal" href="generated/sklearn.linear_model.SGDRegressor.html#sklearn.linear_model.SGDRegressor" title="sklearn.linear_model.SGDRegressor"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.linear_model.SGDRegressor</span></code></a></p></li>
<li><p><a class="reference internal" href="generated/sklearn.linear_model.PassiveAggressiveRegressor.html#sklearn.linear_model.PassiveAggressiveRegressor" title="sklearn.linear_model.PassiveAggressiveRegressor"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.linear_model.PassiveAggressiveRegressor</span></code></a></p></li>
<li><p><a class="reference internal" href="generated/sklearn.neural_network.MLPRegressor.html#sklearn.neural_network.MLPRegressor" title="sklearn.neural_network.MLPRegressor"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.neural_network.MLPRegressor</span></code></a></p></li>
</ul>
</dd>
</dl>
</li>
<li><dl class="simple">
<dt>Clustering</dt><dd><ul>
<li><p><a class="reference internal" href="generated/sklearn.cluster.MiniBatchKMeans.html#sklearn.cluster.MiniBatchKMeans" title="sklearn.cluster.MiniBatchKMeans"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.cluster.MiniBatchKMeans</span></code></a></p></li>
<li><p><a class="reference internal" href="generated/sklearn.cluster.Birch.html#sklearn.cluster.Birch" title="sklearn.cluster.Birch"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.cluster.Birch</span></code></a></p></li>
</ul>
</dd>
</dl>
</li>
<li><dl class="simple">
<dt>Decomposition / feature Extraction</dt><dd><ul>
<li><p><a class="reference internal" href="generated/sklearn.decomposition.MiniBatchDictionaryLearning.html#sklearn.decomposition.MiniBatchDictionaryLearning" title="sklearn.decomposition.MiniBatchDictionaryLearning"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.decomposition.MiniBatchDictionaryLearning</span></code></a></p></li>
<li><p><a class="reference internal" href="generated/sklearn.decomposition.IncrementalPCA.html#sklearn.decomposition.IncrementalPCA" title="sklearn.decomposition.IncrementalPCA"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.decomposition.IncrementalPCA</span></code></a></p></li>
<li><p><a class="reference internal" href="generated/sklearn.decomposition.LatentDirichletAllocation.html#sklearn.decomposition.LatentDirichletAllocation" title="sklearn.decomposition.LatentDirichletAllocation"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.decomposition.LatentDirichletAllocation</span></code></a></p></li>
</ul>
</dd>
</dl>
</li>
<li><dl class="simple">
<dt>Preprocessing</dt><dd><ul>
<li><p><a class="reference internal" href="generated/sklearn.preprocessing.StandardScaler.html#sklearn.preprocessing.StandardScaler" title="sklearn.preprocessing.StandardScaler"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.preprocessing.StandardScaler</span></code></a></p></li>
<li><p><a class="reference internal" href="generated/sklearn.preprocessing.MinMaxScaler.html#sklearn.preprocessing.MinMaxScaler" title="sklearn.preprocessing.MinMaxScaler"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.preprocessing.MinMaxScaler</span></code></a></p></li>
<li><p><a class="reference internal" href="generated/sklearn.preprocessing.MaxAbsScaler.html#sklearn.preprocessing.MaxAbsScaler" title="sklearn.preprocessing.MaxAbsScaler"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.preprocessing.MaxAbsScaler</span></code></a></p></li>
</ul>
</dd>
</dl>
</li>
</ul>
</div></blockquote>
<p>For classification, a somewhat important thing to note is that although a
stateless feature extraction routine may be able to cope with new/unseen
attributes, the incremental learner itself may be unable to cope with
new/unseen targets classes. In this case you have to pass all the possible
classes to the first <code class="docutils literal notranslate"><span class="pre">partial_fit</span></code> call using the <code class="docutils literal notranslate"><span class="pre">classes=</span></code> parameter.</p>
<p>Another aspect to consider when choosing a proper algorithm is that not all of
them put the same importance on each example over time. Namely, the
<code class="docutils literal notranslate"><span class="pre">Perceptron</span></code> is still sensitive to badly labeled examples even after many
examples whereas the <code class="docutils literal notranslate"><span class="pre">SGD*</span></code> and <code class="docutils literal notranslate"><span class="pre">PassiveAggressive*</span></code> families are more
robust to this kind of artifacts. Conversely, the latter also tend to give less
importance to remarkably different, yet properly labeled examples when they
come late in the stream as their learning rate decreases over time.</p>
</div>
<div class="section" id="examples">
<h4>8.1.1.4. Examples<a class="headerlink" href="#examples" title="Permalink to this headline">¶</a></h4>
<p>Finally, we have a full-fledged example of
<a class="reference internal" href="../auto_examples/applications/plot_out_of_core_classification.html#sphx-glr-auto-examples-applications-plot-out-of-core-classification-py"><span class="std std-ref">Out-of-core classification of text documents</span></a>. It is aimed at
providing a starting point for people wanting to build out-of-core learning
systems and demonstrates most of the notions discussed above.</p>
<p>Furthermore, it also shows the evolution of the performance of different
algorithms with the number of processed examples.</p>
<p class="centered">
<strong><a class="reference external" href="../auto_examples/applications/plot_out_of_core_classification.html"><img alt="accuracy_over_time" src="modules/../auto_examples/applications/images/sphx_glr_plot_out_of_core_classification_001.png" /></a></strong></p><p>Now looking at the computation time of the different parts, we see that the
vectorization is much more expensive than learning itself. From the different
algorithms, <code class="docutils literal notranslate"><span class="pre">MultinomialNB</span></code> is the most expensive, but its overhead can be
mitigated by increasing the size of the mini-batches (exercise: change
<code class="docutils literal notranslate"><span class="pre">minibatch_size</span></code> to 100 and 10000 in the program and compare).</p>
<p class="centered">
<strong><a class="reference external" href="../auto_examples/applications/plot_out_of_core_classification.html"><img alt="computation_time" src="modules/../auto_examples/applications/images/sphx_glr_plot_out_of_core_classification_003.png" /></a></strong></p></div>
<div class="section" id="notes">
<h4>8.1.1.5. Notes<a class="headerlink" href="#notes" title="Permalink to this headline">¶</a></h4>
<dl class="footnote brackets">
<dt class="label" id="id2"><span class="brackets"><a class="fn-backref" href="#id1">1</a></span></dt>
<dd><p>Depending on the algorithm the mini-batch size can influence results or
not. SGD*, PassiveAggressive*, and discrete NaiveBayes are truly online
and are not affected by batch size. Conversely, MiniBatchKMeans
convergence rate is affected by the batch size. Also, its memory
footprint can vary dramatically with batch size.</p>
</dd>
</dl>
</div>
</div>
</div>
<div class="section" id="computational-performance">
<span id="id3"></span><h2>8.2. Computational Performance<a class="headerlink" href="#computational-performance" title="Permalink to this headline">¶</a></h2>
<p>For some applications the performance (mainly latency and throughput at
prediction time) of estimators is crucial. It may also be of interest to
consider the training throughput but this is often less important in a
production setup (where it often takes place offline).</p>
<p>We will review here the orders of magnitude you can expect from a number of
scikit-learn estimators in different contexts and provide some tips and
tricks for overcoming performance bottlenecks.</p>
<p>Prediction latency is measured as the elapsed time necessary to make a
prediction (e.g. in micro-seconds). Latency is often viewed as a distribution
and operations engineers often focus on the latency at a given percentile of
this distribution (e.g. the 90 percentile).</p>
<p>Prediction throughput is defined as the number of predictions the software can
deliver in a given amount of time (e.g. in predictions per second).</p>
<p>An important aspect of performance optimization is also that it can hurt
prediction accuracy. Indeed, simpler models (e.g. linear instead of
non-linear, or with fewer parameters) often run faster but are not always able
to take into account the same exact properties of the data as more complex ones.</p>
<div class="section" id="prediction-latency">
<h3>8.2.1. Prediction Latency<a class="headerlink" href="#prediction-latency" title="Permalink to this headline">¶</a></h3>
<p>One of the most straight-forward concerns one may have when using/choosing a
machine learning toolkit is the latency at which predictions can be made in a
production environment.</p>
<dl class="simple">
<dt>The main factors that influence the prediction latency are</dt><dd><ol class="arabic simple">
<li><p>Number of features</p></li>
<li><p>Input data representation and sparsity</p></li>
<li><p>Model complexity</p></li>
<li><p>Feature extraction</p></li>
</ol>
</dd>
</dl>
<p>A last major parameter is also the possibility to do predictions in bulk or
one-at-a-time mode.</p>
<div class="section" id="bulk-versus-atomic-mode">
<h4>8.2.1.1. Bulk versus Atomic mode<a class="headerlink" href="#bulk-versus-atomic-mode" title="Permalink to this headline">¶</a></h4>
<p>In general doing predictions in bulk (many instances at the same time) is
more efficient for a number of reasons (branching predictability, CPU cache,
linear algebra libraries optimizations etc.). Here we see on a setting
with few features that independently of estimator choice the bulk mode is
always faster, and for some of them by 1 to 2 orders of magnitude:</p>
<p class="centered">
<strong><a class="reference external" href="../auto_examples/applications/plot_prediction_latency.html"><img alt="atomic_prediction_latency" src="modules/../auto_examples/applications/images/sphx_glr_plot_prediction_latency_001.png" /></a></strong></p><p class="centered">
<strong><a class="reference external" href="../auto_examples/applications/plot_prediction_latency.html"><img alt="bulk_prediction_latency" src="modules/../auto_examples/applications/images/sphx_glr_plot_prediction_latency_002.png" /></a></strong></p><p>To benchmark different estimators for your case you can simply change the
<code class="docutils literal notranslate"><span class="pre">n_features</span></code> parameter in this example:
<a class="reference internal" href="../auto_examples/applications/plot_prediction_latency.html#sphx-glr-auto-examples-applications-plot-prediction-latency-py"><span class="std std-ref">Prediction Latency</span></a>. This should give
you an estimate of the order of magnitude of the prediction latency.</p>
</div>
<div class="section" id="configuring-scikit-learn-for-reduced-validation-overhead">
<h4>8.2.1.2. Configuring Scikit-learn for reduced validation overhead<a class="headerlink" href="#configuring-scikit-learn-for-reduced-validation-overhead" title="Permalink to this headline">¶</a></h4>
<p>Scikit-learn does some validation on data that increases the overhead per
call to <code class="docutils literal notranslate"><span class="pre">predict</span></code> and similar functions. In particular, checking that
features are finite (not NaN or infinite) involves a full pass over the
data. If you ensure that your data is acceptable, you may suppress
checking for finiteness by setting the environment variable
<code class="docutils literal notranslate"><span class="pre">SKLEARN_ASSUME_FINITE</span></code> to a non-empty string before importing
scikit-learn, or configure it in Python with <a class="reference internal" href="generated/sklearn.set_config.html#sklearn.set_config" title="sklearn.set_config"><code class="xref py py-func docutils literal notranslate"><span class="pre">sklearn.set_config</span></code></a>.
For more control than these global settings, a <code class="xref py py-func docutils literal notranslate"><span class="pre">config_context</span></code>
allows you to set this configuration within a specified context:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">sklearn</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">with</span> <span class="n">sklearn</span><span class="o">.</span><span class="n">config_context</span><span class="p">(</span><span class="n">assume_finite</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
<span class="gp">... </span>    <span class="k">pass</span>  <span class="c1"># do learning/prediction here with reduced validation</span>
</pre></div>
</div>
<p>Note that this will affect all uses of
<a class="reference internal" href="generated/sklearn.utils.assert_all_finite.html#sklearn.utils.assert_all_finite" title="sklearn.utils.assert_all_finite"><code class="xref py py-func docutils literal notranslate"><span class="pre">sklearn.utils.assert_all_finite</span></code></a> within the context.</p>
</div>
<div class="section" id="influence-of-the-number-of-features">
<h4>8.2.1.3. Influence of the Number of Features<a class="headerlink" href="#influence-of-the-number-of-features" title="Permalink to this headline">¶</a></h4>
<p>Obviously when the number of features increases so does the memory
consumption of each example. Indeed, for a matrix of <span class="math notranslate nohighlight">\(M\)</span> instances
with <span class="math notranslate nohighlight">\(N\)</span> features, the space complexity is in <span class="math notranslate nohighlight">\(O(NM)\)</span>.
From a computing perspective it also means that the number of basic operations
(e.g., multiplications for vector-matrix products in linear models) increases
too. Here is a graph of the evolution of the prediction latency with the
number of features:</p>
<p class="centered">
<strong><a class="reference external" href="../auto_examples/applications/plot_prediction_latency.html"><img alt="influence_of_n_features_on_latency" src="modules/../auto_examples/applications/images/sphx_glr_plot_prediction_latency_003.png" /></a></strong></p><p>Overall you can expect the prediction time to increase at least linearly with
the number of features (non-linear cases can happen depending on the global
memory footprint and estimator).</p>
</div>
<div class="section" id="influence-of-the-input-data-representation">
<h4>8.2.1.4. Influence of the Input Data Representation<a class="headerlink" href="#influence-of-the-input-data-representation" title="Permalink to this headline">¶</a></h4>
<p>Scipy provides sparse matrix data structures which are optimized for storing
sparse data. The main feature of sparse formats is that you don’t store zeros
so if your data is sparse then you use much less memory. A non-zero value in
a sparse (<a class="reference external" href="https://docs.scipy.org/doc/scipy/reference/sparse.html">CSR or CSC</a>)
representation will only take on average one 32bit integer position + the 64
bit floating point value + an additional 32bit per row or column in the matrix.
Using sparse input on a dense (or sparse) linear model can speedup prediction
by quite a bit as only the non zero valued features impact the dot product
and thus the model predictions. Hence if you have 100 non zeros in 1e6
dimensional space, you only need 100 multiply and add operation instead of 1e6.</p>
<p>Calculation over a dense representation, however, may leverage highly optimised
vector operations and multithreading in BLAS, and tends to result in fewer CPU
cache misses. So the sparsity should typically be quite high (10% non-zeros
max, to be checked depending on the hardware) for the sparse input
representation to be faster than the dense input representation on a machine
with many CPUs and an optimized BLAS implementation.</p>
<p>Here is sample code to test the sparsity of your input:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">sparsity_ratio</span><span class="p">(</span><span class="n">X</span><span class="p">):</span>
    <span class="k">return</span> <span class="mf">1.0</span> <span class="o">-</span> <span class="n">np</span><span class="o">.</span><span class="n">count_nonzero</span><span class="p">(</span><span class="n">X</span><span class="p">)</span> <span class="o">/</span> <span class="nb">float</span><span class="p">(</span><span class="n">X</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">X</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;input sparsity ratio:&quot;</span><span class="p">,</span> <span class="n">sparsity_ratio</span><span class="p">(</span><span class="n">X</span><span class="p">))</span>
</pre></div>
</div>
<p>As a rule of thumb you can consider that if the sparsity ratio is greater
than 90% you can probably benefit from sparse formats. Check Scipy’s sparse
matrix formats <a class="reference external" href="https://docs.scipy.org/doc/scipy/reference/sparse.html">documentation</a>
for more information on how to build (or convert your data to) sparse matrix
formats. Most of the time the <code class="docutils literal notranslate"><span class="pre">CSR</span></code> and <code class="docutils literal notranslate"><span class="pre">CSC</span></code> formats work best.</p>
</div>
<div class="section" id="influence-of-the-model-complexity">
<h4>8.2.1.5. Influence of the Model Complexity<a class="headerlink" href="#influence-of-the-model-complexity" title="Permalink to this headline">¶</a></h4>
<p>Generally speaking, when model complexity increases, predictive power and
latency are supposed to increase. Increasing predictive power is usually
interesting, but for many applications we would better not increase
prediction latency too much. We will now review this idea for different
families of supervised models.</p>
<p>For <a class="reference internal" href="classes.html#module-sklearn.linear_model" title="sklearn.linear_model"><code class="xref py py-mod docutils literal notranslate"><span class="pre">sklearn.linear_model</span></code></a> (e.g. Lasso, ElasticNet,
SGDClassifier/Regressor, Ridge &amp; RidgeClassifier,
PassiveAggressiveClassifier/Regressor, LinearSVC, LogisticRegression…) the
decision function that is applied at prediction time is the same (a dot product)
, so latency should be equivalent.</p>
<p>Here is an example using
<a class="reference internal" href="generated/sklearn.linear_model.SGDClassifier.html#sklearn.linear_model.SGDClassifier" title="sklearn.linear_model.SGDClassifier"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.linear_model.SGDClassifier</span></code></a> with the
<code class="docutils literal notranslate"><span class="pre">elasticnet</span></code> penalty. The regularization strength is globally controlled by
the <code class="docutils literal notranslate"><span class="pre">alpha</span></code> parameter. With a sufficiently high <code class="docutils literal notranslate"><span class="pre">alpha</span></code>,
one can then increase the <code class="docutils literal notranslate"><span class="pre">l1_ratio</span></code> parameter of <code class="docutils literal notranslate"><span class="pre">elasticnet</span></code> to
enforce various levels of sparsity in the model coefficients. Higher sparsity
here is interpreted as less model complexity as we need fewer coefficients to
describe it fully. Of course sparsity influences in turn the prediction time
as the sparse dot-product takes time roughly proportional to the number of
non-zero coefficients.</p>
<p class="centered">
<strong><a class="reference external" href="../auto_examples/applications/plot_model_complexity_influence.html"><img alt="en_model_complexity" src="modules/../auto_examples/applications/images/sphx_glr_plot_model_complexity_influence_001.png" /></a></strong></p><p>For the <a class="reference internal" href="classes.html#module-sklearn.svm" title="sklearn.svm"><code class="xref py py-mod docutils literal notranslate"><span class="pre">sklearn.svm</span></code></a> family of algorithms with a non-linear kernel,
the latency is tied to the number of support vectors (the fewer the faster).
Latency and throughput should (asymptotically) grow linearly with the number
of support vectors in a SVC or SVR model. The kernel will also influence the
latency as it is used to compute the projection of the input vector once per
support vector. In the following graph the <code class="docutils literal notranslate"><span class="pre">nu</span></code> parameter of
<a class="reference internal" href="generated/sklearn.svm.NuSVR.html#sklearn.svm.NuSVR" title="sklearn.svm.NuSVR"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.svm.NuSVR</span></code></a> was used to influence the number of
support vectors.</p>
<p class="centered">
<strong><a class="reference external" href="../auto_examples/applications/plot_model_complexity_influence.html"><img alt="nusvr_model_complexity" src="modules/../auto_examples/applications/images/sphx_glr_plot_model_complexity_influence_002.png" /></a></strong></p><p>For <a class="reference internal" href="classes.html#module-sklearn.ensemble" title="sklearn.ensemble"><code class="xref py py-mod docutils literal notranslate"><span class="pre">sklearn.ensemble</span></code></a> of trees (e.g. RandomForest, GBT,
ExtraTrees etc) the number of trees and their depth play the most
important role. Latency and throughput should scale linearly with the number
of trees. In this case we used directly the <code class="docutils literal notranslate"><span class="pre">n_estimators</span></code> parameter of
<code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.ensemble.gradient_boosting.GradientBoostingRegressor</span></code>.</p>
<p class="centered">
<strong><a class="reference external" href="../auto_examples/applications/plot_model_complexity_influence.html"><img alt="gbt_model_complexity" src="modules/../auto_examples/applications/images/sphx_glr_plot_model_complexity_influence_003.png" /></a></strong></p><p>In any case be warned that decreasing model complexity can hurt accuracy as
mentioned above. For instance a non-linearly separable problem can be handled
with a speedy linear model but prediction power will very likely suffer in
the process.</p>
</div>
<div class="section" id="feature-extraction-latency">
<h4>8.2.1.6. Feature Extraction Latency<a class="headerlink" href="#feature-extraction-latency" title="Permalink to this headline">¶</a></h4>
<p>Most scikit-learn models are usually pretty fast as they are implemented
either with compiled Cython extensions or optimized computing libraries.
On the other hand, in many real world applications the feature extraction
process (i.e. turning raw data like database rows or network packets into
numpy arrays) governs the overall prediction time. For example on the Reuters
text classification task the whole preparation (reading and parsing SGML
files, tokenizing the text and hashing it into a common vector space) is
taking 100 to 500 times more time than the actual prediction code, depending on
the chosen model.</p>
<blockquote>
<div></div></blockquote>
<p class="centered">
<strong><a class="reference external" href="../auto_examples/applications/plot_out_of_core_classification.html"><img alt="prediction_time" src="modules/../auto_examples/applications/images/sphx_glr_plot_out_of_core_classification_004.png" /></a></strong></p><p>In many cases it is thus recommended to carefully time and profile your
feature extraction code as it may be a good place to start optimizing when
your overall latency is too slow for your application.</p>
</div>
</div>
<div class="section" id="prediction-throughput">
<h3>8.2.2. Prediction Throughput<a class="headerlink" href="#prediction-throughput" title="Permalink to this headline">¶</a></h3>
<p>Another important metric to care about when sizing production systems is the
throughput i.e. the number of predictions you can make in a given amount of
time. Here is a benchmark from the
<a class="reference internal" href="../auto_examples/applications/plot_prediction_latency.html#sphx-glr-auto-examples-applications-plot-prediction-latency-py"><span class="std std-ref">Prediction Latency</span></a> example that measures
this quantity for a number of estimators on synthetic data:</p>
<p class="centered">
<strong><a class="reference external" href="../auto_examples/applications/plot_prediction_latency.html"><img alt="throughput_benchmark" src="modules/../auto_examples/applications/images/sphx_glr_plot_prediction_latency_004.png" /></a></strong></p><p>These throughputs are achieved on a single process. An obvious way to
increase the throughput of your application is to spawn additional instances
(usually processes in Python because of the
<a class="reference external" href="https://wiki.python.org/moin/GlobalInterpreterLock">GIL</a>) that share the
same model. One might also add machines to spread the load. A detailed
explanation on how to achieve this is beyond the scope of this documentation
though.</p>
</div>
<div class="section" id="tips-and-tricks">
<h3>8.2.3. Tips and Tricks<a class="headerlink" href="#tips-and-tricks" title="Permalink to this headline">¶</a></h3>
<div class="section" id="linear-algebra-libraries">
<h4>8.2.3.1. Linear algebra libraries<a class="headerlink" href="#linear-algebra-libraries" title="Permalink to this headline">¶</a></h4>
<p>As scikit-learn relies heavily on Numpy/Scipy and linear algebra in general it
makes sense to take explicit care of the versions of these libraries.
Basically, you ought to make sure that Numpy is built using an optimized <a class="reference external" href="https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms">BLAS</a> /
<a class="reference external" href="https://en.wikipedia.org/wiki/LAPACK">LAPACK</a> library.</p>
<p>Not all models benefit from optimized BLAS and Lapack implementations. For
instance models based on (randomized) decision trees typically do not rely on
BLAS calls in their inner loops, nor do kernel SVMs (<code class="docutils literal notranslate"><span class="pre">SVC</span></code>, <code class="docutils literal notranslate"><span class="pre">SVR</span></code>,
<code class="docutils literal notranslate"><span class="pre">NuSVC</span></code>, <code class="docutils literal notranslate"><span class="pre">NuSVR</span></code>).  On the other hand a linear model implemented with a
BLAS DGEMM call (via <code class="docutils literal notranslate"><span class="pre">numpy.dot</span></code>) will typically benefit hugely from a tuned
BLAS implementation and lead to orders of magnitude speedup over a
non-optimized BLAS.</p>
<p>You can display the BLAS / LAPACK implementation used by your NumPy / SciPy /
scikit-learn install with the following commands:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">numpy.distutils.system_info</span> <span class="kn">import</span> <span class="n">get_info</span>
<span class="nb">print</span><span class="p">(</span><span class="n">get_info</span><span class="p">(</span><span class="s1">&#39;blas_opt&#39;</span><span class="p">))</span>
<span class="nb">print</span><span class="p">(</span><span class="n">get_info</span><span class="p">(</span><span class="s1">&#39;lapack_opt&#39;</span><span class="p">))</span>
</pre></div>
</div>
<dl class="simple">
<dt>Optimized BLAS / LAPACK implementations include:</dt><dd><ul class="simple">
<li><p>Atlas (need hardware specific tuning by rebuilding on the target machine)</p></li>
<li><p>OpenBLAS</p></li>
<li><p>MKL</p></li>
<li><p>Apple Accelerate and vecLib frameworks (OSX only)</p></li>
</ul>
</dd>
</dl>
<p>More information can be found on the <a class="reference external" href="https://docs.scipy.org/doc/numpy/user/install.html">Scipy install page</a>
and in this
<a class="reference external" href="http://danielnouri.org/notes/2012/12/19/libblas-and-liblapack-issues-and-speed,-with-scipy-and-ubuntu/">blog post</a>
from Daniel Nouri which has some nice step by step install instructions for
Debian / Ubuntu.</p>
</div>
<div class="section" id="limiting-working-memory">
<span id="working-memory"></span><h4>8.2.3.2. Limiting Working Memory<a class="headerlink" href="#limiting-working-memory" title="Permalink to this headline">¶</a></h4>
<p>Some calculations when implemented using standard numpy vectorized operations
involve using a large amount of temporary memory.  This may potentially exhaust
system memory.  Where computations can be performed in fixed-memory chunks, we
attempt to do so, and allow the user to hint at the maximum size of this
working memory (defaulting to 1GB) using <a class="reference internal" href="generated/sklearn.set_config.html#sklearn.set_config" title="sklearn.set_config"><code class="xref py py-func docutils literal notranslate"><span class="pre">sklearn.set_config</span></code></a> or
<code class="xref py py-func docutils literal notranslate"><span class="pre">config_context</span></code>.  The following suggests to limit temporary working
memory to 128 MiB:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">sklearn</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">with</span> <span class="n">sklearn</span><span class="o">.</span><span class="n">config_context</span><span class="p">(</span><span class="n">working_memory</span><span class="o">=</span><span class="mi">128</span><span class="p">):</span>
<span class="gp">... </span>    <span class="k">pass</span>  <span class="c1"># do chunked work here</span>
</pre></div>
</div>
<p>An example of a chunked operation adhering to this setting is
<code class="xref py py-func docutils literal notranslate"><span class="pre">metric.pairwise_distances_chunked</span></code>, which facilitates computing
row-wise reductions of a pairwise distance matrix.</p>
</div>
<div class="section" id="model-compression">
<h4>8.2.3.3. Model Compression<a class="headerlink" href="#model-compression" title="Permalink to this headline">¶</a></h4>
<p>Model compression in scikit-learn only concerns linear models for the moment.
In this context it means that we want to control the model sparsity (i.e. the
number of non-zero coordinates in the model vectors). It is generally a good
idea to combine model sparsity with sparse input data representation.</p>
<p>Here is sample code that illustrates the use of the <code class="docutils literal notranslate"><span class="pre">sparsify()</span></code> method:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">clf</span> <span class="o">=</span> <span class="n">SGDRegressor</span><span class="p">(</span><span class="n">penalty</span><span class="o">=</span><span class="s1">&#39;elasticnet&#39;</span><span class="p">,</span> <span class="n">l1_ratio</span><span class="o">=</span><span class="mf">0.25</span><span class="p">)</span>
<span class="n">clf</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X_train</span><span class="p">,</span> <span class="n">y_train</span><span class="p">)</span><span class="o">.</span><span class="n">sparsify</span><span class="p">()</span>
<span class="n">clf</span><span class="o">.</span><span class="n">predict</span><span class="p">(</span><span class="n">X_test</span><span class="p">)</span>
</pre></div>
</div>
<p>In this example we prefer the <code class="docutils literal notranslate"><span class="pre">elasticnet</span></code> penalty as it is often a good
compromise between model compactness and prediction power. One can also
further tune the <code class="docutils literal notranslate"><span class="pre">l1_ratio</span></code> parameter (in combination with the
regularization strength <code class="docutils literal notranslate"><span class="pre">alpha</span></code>) to control this tradeoff.</p>
<p>A typical <a class="reference external" href="https://github.com/scikit-learn/scikit-learn/blob/master/benchmarks/bench_sparsify.py">benchmark</a>
on synthetic data yields a &gt;30% decrease in latency when both the model and
input are sparse (with 0.000024 and 0.027400 non-zero coefficients ratio
respectively). Your mileage may vary depending on the sparsity and size of
your data and model.
Furthermore, sparsifying can be very useful to reduce the memory usage of
predictive models deployed on production servers.</p>
</div>
<div class="section" id="model-reshaping">
<h4>8.2.3.4. Model Reshaping<a class="headerlink" href="#model-reshaping" title="Permalink to this headline">¶</a></h4>
<p>Model reshaping consists in selecting only a portion of the available features
to fit a model. In other words, if a model discards features during the
learning phase we can then strip those from the input. This has several
benefits. Firstly it reduces memory (and therefore time) overhead of the
model itself. It also allows to discard explicit
feature selection components in a pipeline once we know which features to
keep from a previous run. Finally, it can help reduce processing time and I/O
usage upstream in the data access and feature extraction layers by not
collecting and building features that are discarded by the model. For instance
if the raw data come from a database, it can make it possible to write simpler
and faster queries or reduce I/O usage by making the queries return lighter
records.
At the moment, reshaping needs to be performed manually in scikit-learn.
In the case of sparse input (particularly in <code class="docutils literal notranslate"><span class="pre">CSR</span></code> format), it is generally
sufficient to not generate the relevant features, leaving their columns empty.</p>
</div>
<div class="section" id="links">
<h4>8.2.3.5. Links<a class="headerlink" href="#links" title="Permalink to this headline">¶</a></h4>
<blockquote>
<div><ul class="simple">
<li><p><a class="reference internal" href="../developers/performance.html#performance-howto"><span class="std std-ref">scikit-learn developer performance documentation</span></a></p></li>
<li><p><a class="reference external" href="https://docs.scipy.org/doc/scipy/reference/sparse.html">Scipy sparse matrix formats documentation</a></p></li>
</ul>
</div></blockquote>
</div>
</div>
</div>
<div class="section" id="parallelism-resource-management-and-configuration">
<h2>8.3. Parallelism, resource management, and configuration<a class="headerlink" href="#parallelism-resource-management-and-configuration" title="Permalink to this headline">¶</a></h2>
<div class="section" id="parallelism">
<span id="id4"></span><h3>8.3.1. Parallelism<a class="headerlink" href="#parallelism" title="Permalink to this headline">¶</a></h3>
<p>Some scikit-learn estimators and utilities can parallelize costly operations
using multiple CPU cores, thanks to the following components:</p>
<ul class="simple">
<li><p>via the <a class="reference external" href="https://joblib.readthedocs.io/en/latest/">joblib</a> library. In
this case the number of threads or processes can be controlled with the
<code class="docutils literal notranslate"><span class="pre">n_jobs</span></code> parameter.</p></li>
<li><p>via OpenMP, used in C or Cython code.</p></li>
</ul>
<p>In addition, some of the numpy routines that are used internally by
scikit-learn may also be parallelized if numpy is installed with specific
numerical libraries such as MKL, OpenBLAS, or BLIS.</p>
<p>We describe these 3 scenarios in the following subsections.</p>
<div class="section" id="joblib-based-parallelism">
<h4>8.3.1.1. Joblib-based parallelism<a class="headerlink" href="#joblib-based-parallelism" title="Permalink to this headline">¶</a></h4>
<p>When the underlying implementation uses joblib, the number of workers
(threads or processes) that are spawned in parallel can be controlled via the
<code class="docutils literal notranslate"><span class="pre">n_jobs</span></code> parameter.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Where (and how) parallelization happens in the estimators is currently
poorly documented. Please help us by improving our docs and tackle <a class="reference external" href="https://github.com/scikit-learn/scikit-learn/issues/14228">issue
14228</a>!</p>
</div>
<p>Joblib is able to support both multi-processing and multi-threading. Whether
joblib chooses to spawn a thread or a process depends on the <strong>backend</strong>
that it’s using.</p>
<p>Scikit-learn generally relies on the <code class="docutils literal notranslate"><span class="pre">loky</span></code> backend, which is joblib’s
default backend. Loky is a multi-processing backend. When doing
multi-processing, in order to avoid duplicating the memory in each process
(which isn’t reasonable with big datasets), joblib will create a <a class="reference external" href="https://docs.scipy.org/doc/numpy/reference/generated/numpy.memmap.html">memmap</a>
that all processes can share, when the data is bigger than 1MB.</p>
<p>In some specific cases (when the code that is run in parallel releases the
GIL), scikit-learn will indicate to <code class="docutils literal notranslate"><span class="pre">joblib</span></code> that a multi-threading
backend is preferable.</p>
<p>As a user, you may control the backend that joblib will use (regardless of
what scikit-learn recommends) by using a context manager:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">joblib</span> <span class="kn">import</span> <span class="n">parallel_backend</span>

<span class="k">with</span> <span class="n">parallel_backend</span><span class="p">(</span><span class="s1">&#39;threading&#39;</span><span class="p">,</span> <span class="n">n_jobs</span><span class="o">=</span><span class="mi">2</span><span class="p">):</span>
    <span class="c1"># Your scikit-learn code here</span>
</pre></div>
</div>
<p>Please refer to the <a class="reference external" href="https://joblib.readthedocs.io/en/latest/parallel.html#thread-based-parallelism-vs-process-based-parallelism">joblib’s docs</a>
for more details.</p>
<p>In practice, whether parallelism is helpful at improving runtime depends on
many factors. It is usually a good idea to experiment rather than assuming
that increasing the number of workers is always a good thing. In some cases
it can be highly detrimental to performance to run multiple copies of some
estimators or functions in parallel (see oversubscription below).</p>
</div>
<div class="section" id="openmp-based-parallelism">
<h4>8.3.1.2. OpenMP-based parallelism<a class="headerlink" href="#openmp-based-parallelism" title="Permalink to this headline">¶</a></h4>
<p>OpenMP is used to parallelize code written in Cython or C, relying on
multi-threading exclusively. By default (and unless joblib is trying to
avoid oversubscription), the implementation will use as many threads as
possible.</p>
<p>You can control the exact number of threads that are used via the
<code class="docutils literal notranslate"><span class="pre">OMP_NUM_THREADS</span></code> environment variable:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">OMP_NUM_THREADS</span><span class="o">=</span><span class="mi">4</span> <span class="n">python</span> <span class="n">my_script</span><span class="o">.</span><span class="n">py</span>
</pre></div>
</div>
</div>
<div class="section" id="parallel-numpy-routines-from-numerical-libraries">
<h4>8.3.1.3. Parallel Numpy routines from numerical libraries<a class="headerlink" href="#parallel-numpy-routines-from-numerical-libraries" title="Permalink to this headline">¶</a></h4>
<p>Scikit-learn relies heavily on NumPy and SciPy, which internally call
multi-threaded linear algebra routines implemented in libraries such as MKL,
OpenBLAS or BLIS.</p>
<p>The number of threads used by the OpenBLAS, MKL or BLIS libraries can be set
via the <code class="docutils literal notranslate"><span class="pre">MKL_NUM_THREADS</span></code>, <code class="docutils literal notranslate"><span class="pre">OPENBLAS_NUM_THREADS</span></code>, and
<code class="docutils literal notranslate"><span class="pre">BLIS_NUM_THREADS</span></code> environment variables.</p>
<p>Please note that scikit-learn has no direct control over these
implementations. Scikit-learn solely relies on Numpy and Scipy.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>At the time of writing (2019), NumPy and SciPy packages distributed on
pypi.org (used by <code class="docutils literal notranslate"><span class="pre">pip</span></code>) and on the conda-forge channel are linked
with OpenBLAS, while conda packages shipped on the “defaults” channel
from anaconda.org are linked by default with MKL.</p>
</div>
</div>
<div class="section" id="oversubscription-spawning-too-many-threads">
<h4>8.3.1.4. Oversubscription: spawning too many threads<a class="headerlink" href="#oversubscription-spawning-too-many-threads" title="Permalink to this headline">¶</a></h4>
<p>It is generally recommended to avoid using significantly more processes or
threads than the number of CPUs on a machine. Over-subscription happens when
a program is running too many threads at the same time.</p>
<p>Suppose you have a machine with 8 CPUs. Consider a case where you’re running
a <code class="xref py py-class docutils literal notranslate"><span class="pre">GridSearchCV</span></code> (parallelized with joblib) with <code class="docutils literal notranslate"><span class="pre">n_jobs=8</span></code> over
a <code class="xref py py-class docutils literal notranslate"><span class="pre">HistGradientBoostingClassifier</span></code> (parallelized with OpenMP). Each
instance of <code class="xref py py-class docutils literal notranslate"><span class="pre">HistGradientBoostingClassifier</span></code> will spawn 8 threads
(since you have 8 CPUs). That’s a total of <code class="docutils literal notranslate"><span class="pre">8</span> <span class="pre">*</span> <span class="pre">8</span> <span class="pre">=</span> <span class="pre">64</span></code> threads, which
leads to oversubscription of physical CPU resources and to scheduling
overhead.</p>
<p>Oversubscription can arise in the exact same fashion with parallelized
routines from MKL, OpenBLAS or BLIS that are nested in joblib calls.</p>
<p>Starting from <code class="docutils literal notranslate"><span class="pre">joblib</span> <span class="pre">&gt;=</span> <span class="pre">0.14</span></code>, when the <code class="docutils literal notranslate"><span class="pre">loky</span></code> backend is used (which
is the default), joblib will tell its child <strong>processes</strong> to limit the
number of threads they can use, so as to avoid oversubscription. In practice
the heuristic that joblib uses is to tell the processes to use <code class="docutils literal notranslate"><span class="pre">max_threads</span>
<span class="pre">=</span> <span class="pre">n_cpus</span> <span class="pre">//</span> <span class="pre">n_jobs</span></code>, via their corresponding environment variable. Back to
our example from above, since the joblib backend of <code class="xref py py-class docutils literal notranslate"><span class="pre">GridSearchCV</span></code>
is <code class="docutils literal notranslate"><span class="pre">loky</span></code>, each process will only be able to use 1 thread instead of 8,
thus mitigating the oversubscription issue.</p>
<p>Note that:</p>
<ul class="simple">
<li><p>Manually setting one of the environment variables (<code class="docutils literal notranslate"><span class="pre">OMP_NUM_THREADS</span></code>,
<code class="docutils literal notranslate"><span class="pre">MKL_NUM_THREADS</span></code>, <code class="docutils literal notranslate"><span class="pre">OPENBLAS_NUM_THREADS</span></code>, or <code class="docutils literal notranslate"><span class="pre">BLIS_NUM_THREADS</span></code>)
will take precedence over what joblib tries to do. The total number of
threads will be <code class="docutils literal notranslate"><span class="pre">n_jobs</span> <span class="pre">*</span> <span class="pre">&lt;LIB&gt;_NUM_THREADS</span></code>. Note that setting this
limit will also impact your computations in the main process, which will
only use <code class="docutils literal notranslate"><span class="pre">&lt;LIB&gt;_NUM_THREADS</span></code>. Joblib exposes a context manager for
finer control over the number of threads in its workers (see joblib docs
linked below).</p></li>
<li><p>Joblib is currently unable to avoid oversubscription in a
multi-threading context. It can only do so with the <code class="docutils literal notranslate"><span class="pre">loky</span></code> backend
(which spawns processes).</p></li>
</ul>
<p>You will find additional details about joblib mitigation of oversubscription
in <a class="reference external" href="https://joblib.readthedocs.io/en/latest/parallel.html#avoiding-over-subscription-of-cpu-ressources">joblib documentation</a>.</p>
</div>
</div>
<div class="section" id="configuration-switches">
<h3>8.3.2. Configuration switches<a class="headerlink" href="#configuration-switches" title="Permalink to this headline">¶</a></h3>
<div class="section" id="python-runtime">
<h4>8.3.2.1. Python runtime<a class="headerlink" href="#python-runtime" title="Permalink to this headline">¶</a></h4>
<p><a class="reference internal" href="generated/sklearn.set_config.html#sklearn.set_config" title="sklearn.set_config"><code class="xref py py-func docutils literal notranslate"><span class="pre">sklearn.set_config</span></code></a> controls the following behaviors:</p>
<dl class="field-list simple">
<dt class="field-odd">assume_finite</dt>
<dd class="field-odd"><p>used to skip validation, which enables faster computations but may
lead to segmentation faults if the data contains NaNs.</p>
</dd>
<dt class="field-even">working_memory</dt>
<dd class="field-even"><p>the optimal size of temporary arrays used by some algorithms.</p>
</dd>
</dl>
</div>
<div class="section" id="environment-variables">
<span id="environment-variable"></span><h4>8.3.2.2. Environment variables<a class="headerlink" href="#environment-variables" title="Permalink to this headline">¶</a></h4>
<p>These environment variables should be set before importing scikit-learn.</p>
<dl class="field-list">
<dt class="field-odd">SKLEARN_SITE_JOBLIB</dt>
<dd class="field-odd"><p>When this environment variable is set to a non zero value,
scikit-learn uses the site joblib rather than its vendored version.
Consequently, joblib must be installed for scikit-learn to run.
Note that using the site joblib is at your own risks: the versions of
scikit-learn and joblib need to be compatible. Currently, joblib 0.11+
is supported. In addition, dumps from joblib.Memory might be incompatible,
and you might loose some caches and have to redownload some datasets.</p>
<div class="deprecated">
<p><span class="versionmodified deprecated">Deprecated since version 0.21: </span>As of version 0.21 this parameter has no effect, vendored joblib was
removed and site joblib is always used.</p>
</div>
</dd>
<dt class="field-even">SKLEARN_ASSUME_FINITE</dt>
<dd class="field-even"><p>Sets the default value for the <code class="docutils literal notranslate"><span class="pre">assume_finite</span></code> argument of
<a class="reference internal" href="generated/sklearn.set_config.html#sklearn.set_config" title="sklearn.set_config"><code class="xref py py-func docutils literal notranslate"><span class="pre">sklearn.set_config</span></code></a>.</p>
</dd>
<dt class="field-odd">SKLEARN_WORKING_MEMORY</dt>
<dd class="field-odd"><p>Sets the default value for the <code class="docutils literal notranslate"><span class="pre">working_memory</span></code> argument of
<a class="reference internal" href="generated/sklearn.set_config.html#sklearn.set_config" title="sklearn.set_config"><code class="xref py py-func docutils literal notranslate"><span class="pre">sklearn.set_config</span></code></a>.</p>
</dd>
<dt class="field-even">SKLEARN_SEED</dt>
<dd class="field-even"><p>Sets the seed of the global random generator when running the tests,
for reproducibility.</p>
</dd>
<dt class="field-odd">SKLEARN_SKIP_NETWORK_TESTS</dt>
<dd class="field-odd"><p>When this environment variable is set to a non zero value, the tests
that need network access are skipped.</p>
</dd>
</dl>
</div>
</div>
</div>
</div>


      </div>
    <div class="container">
      <footer class="sk-content-footer">
            &copy; 2007 - 2019, scikit-learn developers (BSD License).
          <a href="../_sources/modules/computing.rst.txt" rel="nofollow">Show this page source</a>
      </footer>
    </div>
  </div>
</div>
<script src="../_static/js/vendor/bootstrap.min.js"></script>

<script>
    window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
    ga('create', 'UA-22606712-2', 'auto');
    ga('set', 'anonymizeIp', true);
    ga('send', 'pageview');
</script>
<script async src='https://www.google-analytics.com/analytics.js'></script>


<script>
$(document).ready(function() {
    /* Add a [>>>] button on the top-right corner of code samples to hide
     * the >>> and ... prompts and the output and thus make the code
     * copyable. */
    var div = $('.highlight-python .highlight,' +
                '.highlight-python3 .highlight,' +
                '.highlight-pycon .highlight,' +
		'.highlight-default .highlight')
    var pre = div.find('pre');

    // get the styles from the current theme
    pre.parent().parent().css('position', 'relative');
    var hide_text = 'Hide prompts and outputs';
    var show_text = 'Show prompts and outputs';

    // create and add the button to all the code blocks that contain >>>
    div.each(function(index) {
        var jthis = $(this);
        if (jthis.find('.gp').length > 0) {
            var button = $('<span class="copybutton">&gt;&gt;&gt;</span>');
            button.attr('title', hide_text);
            button.data('hidden', 'false');
            jthis.prepend(button);
        }
        // tracebacks (.gt) contain bare text elements that need to be
        // wrapped in a span to work with .nextUntil() (see later)
        jthis.find('pre:has(.gt)').contents().filter(function() {
            return ((this.nodeType == 3) && (this.data.trim().length > 0));
        }).wrap('<span>');
    });

    // define the behavior of the button when it's clicked
    $('.copybutton').click(function(e){
        e.preventDefault();
        var button = $(this);
        if (button.data('hidden') === 'false') {
            // hide the code output
            button.parent().find('.go, .gp, .gt').hide();
            button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'hidden');
            button.css('text-decoration', 'line-through');
            button.attr('title', show_text);
            button.data('hidden', 'true');
        } else {
            // show the code output
            button.parent().find('.go, .gp, .gt').show();
            button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'visible');
            button.css('text-decoration', 'none');
            button.attr('title', hide_text);
            button.data('hidden', 'false');
        }
    });

	/*** Add permalink buttons next to glossary terms ***/
	$('dl.glossary > dt[id]').append(function() {
		return ('<a class="headerlink" href="#' +
			    this.getAttribute('id') +
			    '" title="Permalink to this term">¶</a>');
	});
  /*** Hide navbar when scrolling down ***/
  // Returns true when headerlink target matches hash in url
  (function() {
    hashTargetOnTop = function() {
        var hash = window.location.hash;
        if ( hash.length < 2 ) { return false; }

        var target = document.getElementById( hash.slice(1) );
        if ( target === null ) { return false; }

        var top = target.getBoundingClientRect().top;
        return (top < 2) && (top > -2);
    };

    // Hide navbar on load if hash target is on top
    var navBar = document.getElementById("navbar");
    var navBarToggler = document.getElementById("sk-navbar-toggler");
    var navBarHeightHidden = "-" + navBar.getBoundingClientRect().height + "px";
    var $window = $(window);

    hideNavBar = function() {
        navBar.style.top = navBarHeightHidden;
    };

    showNavBar = function() {
        navBar.style.top = "0";
    }

    if (hashTargetOnTop()) {
        hideNavBar()
    }

    var prevScrollpos = window.pageYOffset;
    hideOnScroll = function(lastScrollTop) {
        if (($window.width() < 768) && (navBarToggler.getAttribute("aria-expanded") === 'true')) {
            return;
        }
        if (lastScrollTop > 2 && (prevScrollpos <= lastScrollTop) || hashTargetOnTop()){
            hideNavBar()
        } else {
            showNavBar()
        }
        prevScrollpos = lastScrollTop;
    };

    /*** high preformance scroll event listener***/
    var raf = window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        window.oRequestAnimationFrame;
    var lastScrollTop = $window.scrollTop();

    if (raf) {
        loop();
    }

    function loop() {
        var scrollTop = $window.scrollTop();
        if (lastScrollTop === scrollTop) {
            raf(loop);
            return;
        } else {
            lastScrollTop = scrollTop;
            hideOnScroll(lastScrollTop);
            raf(loop);
        }
    }
  })();
});

</script>
    
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>
    
</body>
</html>